using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Text;

using Aphysoft.Vate.Graphics;

namespace Aphysoft.Vate
{
    /// <summary>
    /// Base game class for all the basic game support.
    /// Connects all our helper classes together and makes our life easier!
    /// 
    /// Aspect ratio options:
    /// - 16:10
    /// - 16:9 (HD)
    /// - 4:3
    /// 
    /// </summary>
    public partial class Vate : Microsoft.Xna.Framework.Game
    {
        #region Properties
        /// <summary>
        /// Game platform.
        /// </summary>
        public static PlatformID CurrentPlatform = Environment.OSVersion.Platform;
        /// <summary>
        /// Debug component.
        /// </summary>
        private Debug debug = null;
        #endregion

        #region Constructor
        /// <summary>
        /// Create base game.
        /// </summary>
        /// <param name="windowTitle">Game window title.</param>
        /// <param name="definition">Maximum Definition Size used by Game Mode (not in editor mode).</param>
        protected Vate(string windowTitle, DefinitionSize definition)
        {
            // Graphics setup
            GraphicsSetup();

            // Update as fast as possible, do not use fixed time steps.
            this.IsFixedTimeStep = false;

            // Set window title
            this.Window.Title = windowTitle;

            // Set game definition
            Vate.definition = definition;

            // Init content manager
            Vate.content = base.Content;
            Vate.content.RootDirectory = Vate.ContentRootDirectory;
        }
        #endregion

        #region Initialize

        protected sealed override void Initialize()
        {
            // Apply Resolution
            ApplyResolutionChange();                     
#if DEBUG
            // Debug
            debug = new Debug(10);
            Debug.Write("Debug Initialized.");
#endif              
            // Gamer services
            GamerServicesSetup();

            // camera manager
            CameraManager.Init();

            // projector manager
            ProjectorManager.Init();

            // Initialize as device being reset         
            GraphicsDeviceReset(null, EventArgs.Empty);   
            
            // line manager
            Line.Init();

#if DEBUG
            // transformation debugger
            TransformationDebugger transformationDebugger = new TransformationDebugger();
#endif
            // Init game
            GameInitialize();

            base.Initialize();
        }

        #region Initialize Virtualization
        protected virtual void GameInitialize()
        {
        }
        #endregion

        #endregion

        #region LoadContent

        protected sealed override void LoadContent()
        {
            globalAlphaSpriteBatch = new SpriteBatch(Device);

            globalAdditiveSpriteBatch = new SpriteBatch(Device);

#if DEBUG
            Debug.Write("Loading Content...");
#endif
            GameLoadContent();
#if DEBUG
            Debug.Write("Content Loaded.");
#endif

#if DEBUG
            // Debug load content
            debug.LoadContent();
#endif

            base.LoadContent();
        }

        #region LoadContent Virtualization
        protected virtual void GameLoadContent()
        {
        }
        #endregion

        #endregion

        #region UnloadContent

        protected sealed override void UnloadContent()
        {
            GameUnloadContent();

            globalAlphaSpriteBatch.Dispose();

            base.UnloadContent();
        }

        #region UnloadContent Virtualization
        protected virtual void GameUnloadContent()
        {
        }
        #endregion

        #endregion

        #region Update

        protected sealed override void Update(GameTime gameTime)
        {
            #region Input
            if (IsActive)
            {
                keyboardState = Keyboard.GetState();
                mouseState = Mouse.GetState();
            }
            #endregion

            // Game time update
            Vate.TimeUpdate(gameTime);
#if DEBUG
            // Debug update
            debug.Update(gameTime);
#endif

            base.Update(gameTime);

            GameUpdate(gameTime);

#if PRERENDERED
            // PreRenderedHelper update routine
            PreRenderedHelper.Update();
#endif

            #region Input Finallized
            oldKeyboardState = keyboardState;
            oldMouseState = mouseState;
            #endregion
        }

        #region Update Virtualization
        protected virtual void GameUpdate(GameTime gameTime)
        {
        }
        #endregion

        #endregion

        #region Draw

        /// <summary>
        /// Render delegate for drawing methods, also used for many other methods.
        /// </summary>
        public delegate void DrawHandler();

        protected sealed override void Draw(GameTime gameTime)
        {
            // Begin ProjectorManager
            ProjectorManager.Begin();            

            // Clear
            Vate.Device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.SlateBlue, 1.0f, 0);

            // Begin Global Additive Sprite Batch, Global Alpha Sprite Batch
            GlobalAdditiveSpriteBatch.Begin(SpriteBlendMode.Additive);
            GlobalAlphaSpriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            // Benchmarking
#if DEBUG
            inputTriangle = 0;
#endif
                        
            // Game Draw for Default Projector
            if (ProjectorManager.DefaultProjector.IsRender)
            {
                // Draw Projector Scene
                GameDraw(gameTime);

                // Line Manager
                Line.Draw();
            }

            // Game Draw for other projector in projector manager
            if (ProjectorManager.Projectors.Count > 0)
            {
                foreach (KeyValuePair<string, Projector> projectorEntry in ProjectorManager.Projectors)
                {
                    string gameProjectorName = projectorEntry.Key;
                    Projector gameProjector = projectorEntry.Value;

                    ProjectorManager.Current = gameProjectorName;
                    Device.Viewport = gameProjector.Viewport;                    

                    // Draw Projector Scene
                    GameDraw(gameTime);

                    // Line Manager
                    Line.Draw();
                }
            }

            // End ProjectorManager
            ProjectorManager.End();

#if DEBUG
            // Debug draw
            debug.Draw(gameTime);
#endif

            // Base Draw
            base.Draw(gameTime);            

            // End Global Alpha Sprite Batch, Additive Sprite Batch
            GlobalAlphaSpriteBatch.End();
            GlobalAdditiveSpriteBatch.End();

            // Apply device changes when marked
            if (mustApplyDeviceChanges)
            {
                graphicsManager.ApplyChanges();
                mustApplyDeviceChanges = false;
            }

            // Game time update
            Vate.TimeDraw(gameTime);

#if PRERENDERED
            // PreRenderedHelper draw routine
            PreRenderedHelper.Draw();
#endif
        }

        #region Draw Virtualization
        protected virtual void GameDraw(GameTime gameTime)
        {
        }
        #endregion

        #endregion
    }
}
